Skip to content

fix(orchestrator): Expose pending delegated child work - #4793

Open
mwolson wants to merge 193 commits into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/delegated-task-status-queued-turn
Open

fix(orchestrator): Expose pending delegated child work#4793
mwolson wants to merge 193 commits into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/delegated-task-status-queued-turn

Conversation

@mwolson

@mwolson mwolson commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Expose whether a delegated child thread has later work pending without changing
the established meaning of the original delegation fields.

childRunId, status, summary, and resultContextTransferId stay tied to
the original delegate_task run. New hasPendingChildRuns and
latestTerminal* fields let callers avoid treating a busy child as idle and
inspect its newest meaningful terminal result.

This replaces the earlier broader implementation. The branch no longer changes
current-run selection, per-follow-up result finalization, wake policy, or
task_cancel behavior.

Problem and Fix

Problem and Why it Happened Fix
task_status intentionally reported the original delegated run, but provided no indication that the same child thread had a queued or executing follow-up. A caller could see completed and act on a workspace the child was still changing. Add hasPendingChildRuns, derived from nonterminal runs with a later ordinal than the delegated run, while preserving the original delegation fields.
The original result remains useful while later work is active, but callers could not identify the newest completed follow-up. Add latestTerminalRunId, latestTerminalStatus, latestTerminalSummary, and latestTerminalResultContextTransferId. Rolled-back runs and never-started later cancellations do not displace a meaningful result.
Legacy projections without a subagent_spawn transfer selected the latest child run as the delegated run, which could hide later active work. Preserve the first child run as the delegated run for legacy projections and use run ordinals to identify later work.
Tool documentation did not state that wait mode and primary status fields describe the original delegated run. Document the stable primary fields and the new observability fields in the MCP tool descriptions and orchestration reference.

Validation

  • Focused contract and MCP integration tests: 2 files, 6 tests passed.
  • The existing CTM cancellation-isolation regression remains unchanged and
    passes: cancelling a completed original task does not interrupt a later child
    run.
  • Targeted formatting and lint passed for all six changed files.
  • Contracts typecheck passed.
  • Isolated headless live test with a Claude parent and real Codex child:
    • Original ordinal 1 completed with STATUS_FIRST_DONE.
    • During ordinal 2, primary fields stayed on ordinal 1,
      hasPendingChildRuns was true, and the latest terminal result stayed on
      ordinal 1.
    • After ordinal 2 completed with STATUS_SECOND_DONE, pending became false
      and latestTerminalRunId advanced to ordinal 2 while primary fields
      remained unchanged.
  • GitHub Release Smoke, Mobile Native Static Analysis, CodeRabbit, Cursor
    Bugbot, and Macroscope Effect Service Conventions pass.
  • Test currently fails in five unchanged queued-turn replay assertions from the
    newer t3code/codex-turn-mapping merge result. Check is separately red from
    the known Vite+ stdout panic while printing warnings.

Checklist

  • This PR is small and focused
  • I explained what changed and why

Note

Medium Risk
Extends the orchestrator MCP contract and changes legacy delegated-run selection; impact is limited to delegated-task observability and does not alter auth, cancellation, or wake policy.

Overview
Delegated task_status / delegate_task results now expose follow-up child activity without redefining the original delegation fields. childRunId, status, summary, and resultContextTransferId still describe the original delegated run; hasPendingChildRuns signals queued or running child runs with a higher ordinal, and latestTerminal* fields surface the newest meaningful terminal child run (excluding rolled-back and never-started cancellations).

delegatedTaskRun for legacy projections without a subagent_spawn transfer now pins the first child run instead of the latest, so later follow-ups do not replace the delegated run identity. subagent_result transfer lookup prefers transfers whose sourcePoint.runId matches the run, with a legacy fallback when the delegated run has no run id on the transfer.

Contracts, MCP tool descriptions, orchestration docs, and integration tests were updated for the new result shape and wait-mode documentation (wait blocks on the original delegated run).

Reviewed by Cursor Bugbot for commit b73f59d. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Expose pending delegated child work and latest terminal run details in readTask

  • Adds hasPendingChildRuns and latestTerminal* fields (latestTerminalRunId, latestTerminalStatus, latestTerminalSummary, latestTerminalResultContextTransferId) to the OrchestratorMcpDelegateTaskResult contract and readTask response.
  • Introduces hasPendingChildRuns, latestTerminalResultRun, and canExposeTaskRunResult helpers in OrchestratorMcpService to identify queued/running follow-up child runs and the highest-ordinal meaningful terminal run.
  • Result context transfers are now matched to specific run IDs when available; rolled-back and never-started runs are excluded from latest terminal result derivation.
  • Behavioral Change: the legacy delegated-run fallback (no durable subagent_spawn transfer) now returns childProjection.runs[0] (earliest run) instead of latestRun(childProjection).
  • Adds integration tests covering running, queued, and interrupted child-run states using a new Codex replay transcript fixture.

Macroscope summarized e95b1be.

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6bda0290-698d-4eb9-a3a9-8b2c24549b1d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 28, 2026
@mwolson
mwolson marked this pull request as ready for review July 28, 2026 23:20
@macroscopeapp

macroscopeapp Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR adds a new feature exposing pending child work state (hasPendingChildRuns, latestTerminal* fields) through the delegated task API. While the changes are additive, well-tested, and documented, they introduce new user-facing behavior and runtime logic for the orchestration system that warrants human review.

You can customize Macroscope's approvability policy. Learn more.

@mwolson
mwolson force-pushed the fix/delegated-task-status-queued-turn branch from e1056de to 4df5866 Compare July 30, 2026 03:08
@github-actions github-actions Bot added size:M 30-99 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Jul 30, 2026
@mwolson mwolson changed the title fix(orchestrator): Report current delegated task status fix(orchestrator): Expose pending delegated child work Jul 30, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4df5866. Configure here.

Comment thread apps/server/src/mcp/OrchestratorMcpService.ts Outdated
Comment thread apps/server/src/mcp/OrchestratorMcpService.ts Outdated
juliusmarminge and others added 17 commits August 3, 2026 11:44
Co-authored-by: codex <codex@users.noreply.github.com>
- Initialize provider as unchecked in a pending state
- Update initial probe message to reflect session-local status
- Type the runtime effect with `Scope`
- Build the ACP session runtime without wrapping it in `Effect.scoped`
- Use strict TurnId and ProviderItemId parsing in Codex session routing
- Decode in-memory stdio chunks in streaming mode to avoid split UTF-8 corruption
- Transfer session-owned scopes into adapter state
- Ensure runtime scopes close on stop and startup failure
- Add regression coverage for scoped lifecycle cleanup
- Close the managed native event logger when the adapter layer tears down
- Make session runtime close idempotent with an atomic closed flag
- Add coverage for flushing thread native logs on shutdown
- Use codex app-server snapshots for auth, models, and skills
- Remove legacy CLI/config discovery paths and related helpers
- Update tests for the new provider status flow
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
- Document the target orchestration graph, IDs, lifecycles, and capability model
- Add Codex app-server probe fixtures and update the probe test harness
- Introduce orchestration v2 service interfaces and error types
- Add replay runtime, fixtures, and integration coverage
- Update shared contracts and probe transcripts

Co-authored-by: codex <codex@users.noreply.github.com>
- Add Codex adapter and replay harness wiring
- Introduce in-memory orchestration projections and provider registry
- Expand orchestration contracts for turn and runtime events
Co-authored-by: codex <codex@users.noreply.github.com>
juliusmarminge and others added 20 commits August 3, 2026 11:45
Distinguish queued and steering user messages in the mobile thread feed, matching the web timeline.

Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
- Publish migration lifecycle events during startup
- Show a web toast while legacy threads are restored
- Project retry progress and recovery for Codex and Claude turns
- Sync thread completion markers through server-side visit timestamps
…4963)

Co-authored-by: codex <codex@users.noreply.github.com>
… compaction (pingdotgg#4971)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
- Disable LegendList end-maintenance that could snap after user scrolling
- Cancel stale imperative scrolls and release settled turn anchors
- Stabilize handoff run data to avoid per-event timeline rerenders
…elay

Live profiling of the built app (debugger pause inside the hot sqlite
call) showed AgentAwarenessRelay.publishThread grinding at ~8 full shell
snapshots per second after boot. Two causes:

- streamDomainEvents was eventSink.stream() with no cursor, which
  replays every stored event from genesis before going live — so each
  boot fed the relay the entire event history as fresh activity, and it
  queued a publish per activity-relevant event for hours. It now tails
  from the current high-water mark; the relay's startup snapshot publish
  already covers initial state, and the sink subscribes before reading
  the cursor so no live event is lost.
- publishThreadUnsafe materialized the full shell snapshot to find one
  thread; it now uses getThreadShell (archived/deleted map to the
  tombstone path exactly as the active-list lookup did).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A renderer performance trace showed the minimap strips as a standing
source of main-thread frame work: each strip transitioned
background-color (paint) and width (layout), and both fire constantly —
scrolling or streaming flips a band of in-view states at once, and the
hover fisheye animates several widths at a time — so any interaction
kept a 60fps style/layout/paint pipeline running.

The strip now animates only compositor-friendly properties: width tiers
are scale-x on a fixed-width box, and the in-view highlight is a bright
overlay faded with opacity. The scroll handler also skips no-op
data-in-view attribute writes, which previously re-dirtied style state
for every strip on every scroll tick.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Follow-ups from the main merge:

- Migration numbering: main's 035_ProjectionThreadTitleRegeneration is
  released and keeps its id; this branch's unreleased v2 migrations shift
  to 036-044 instead (a released migration can never be renumbered).
- thread.metadata.update accepts regenerateTitle: true arms an in-flight
  titleRegeneration marker on the thread payload (requestId + startedAt),
  a landing title or explicit false clears it. The marker projects onto
  thread shells and through the client-runtime shell model, so the
  sidebar's Regenerating state works unchanged.
- New ThreadTitleRegenerationService worker reacts to armed markers on
  the live domain-event stream (so ws, MCP, and mobile dispatches all
  behave the same): builds a newest-first conversation digest from the
  v2 projection (8k-char budget, retained attachments — ported from the
  v1 reactor), generates via TextGeneration, and lands the title with a
  follow-up metadata update. Failures clear the marker and log.
- The server advertises threadTitleRegeneration again, and the client
  updateThreadMetadata dispatches regenerateTitle-only updates.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The turn item materialized when a queued run is promoted was emitted
with inputIntent "turn_start", but the deterministic replay driver (and
the recorded queued_turn fixtures) expect "queued_turn" — the mismatch
stalled replay before the queued run could start, leaving run 1 waiting
and run 2 queued forever in all five queued_turn fixtures.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Effect service conventions: ThreadManagementThreadNotSendableError
carried an Archived/NoSteerableRun reason union and switched on
reason._tag inside the message getter. Modelled as two error classes
(ThreadManagementThreadArchivedError, ThreadManagementNoSteerableRunError);
both still map to the MCP thread_not_sendable failure code.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Prevent the title row from shifting when output is revealed
- Preserve panel and compact button sizing
@maria-rcks
maria-rcks force-pushed the t3code/codex-turn-mapping branch from a543fd4 to 378615b Compare August 3, 2026 16:01
@mwolson
mwolson force-pushed the fix/delegated-task-status-queued-turn branch from e87ea74 to b73f59d Compare August 3, 2026 20:16
@github-actions github-actions Bot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Aug 4, 2026
@juliusmarminge
juliusmarminge force-pushed the t3code/codex-turn-mapping branch 2 times, most recently from c5e53c8 to 922f352 Compare August 4, 2026 13:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants